package com.edooteach.api.servcice.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.JsonUtils;
import com.edoomath.entity.course.Course;
import com.edoomath.entity.course.UserCourse;
import com.edoomath.entity.mall.Sku;
import com.edoomath.entity.tecent.WechatOpenid;
import com.edoomath.entity.trade.OrderType;
import com.edoomath.entity.trade.PaymentRequest;
import com.edoomath.entity.trade.PaymentStatus;
import com.edoomath.entity.trade.SalesOrder;
import com.edoomath.entity.trade.SalesOrderAddress;
import com.edoomath.entity.trade.SalesOrderItem;
import com.edoomath.entity.user.User;
import com.edoomath.entity.user.UserAddress;
import com.edoomath.entity.user.UserCredit;
import com.edoomath.entity.user.UserSource;
import com.edoomath.entity.user.consume.ConsumeTag;
import com.edoomath.entity.user.consume.ConsumeType;
import com.edoomath.entity.user.consume.UserConsumeRecorder;
import com.edoomath.entity.user.consume.UserCreditRecorder;
import com.edooteach.api.dao.CourseDao;
import com.edooteach.api.dao.UserDao;
import com.edooteach.api.handler.PaymentHandler;
import com.edooteach.api.servcice.SalesOrderService;

/**
 * 
 * @author mohanlan
 *
 */
@Service("salesOrderService")
public class SalesOrderServiceImpl extends DataServiceImpl<SalesOrder> implements SalesOrderService {
    
    private static final Logger logger = LoggerFactory.getLogger(SalesOrderServiceImpl.class);
    
    @Dao
    private UserDao userDao;
    
    @Dao
    private CourseDao courseDao;
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    @Autowired
    private PaymentHandler      paymentHandler;
    
    /*
     * (non-Javadoc)
     * @see com.edooteach.api.servcice.SalesOrderService#list(com.edoomath.entity.user.User)
     */
    @SuppressWarnings("unchecked")
    public List<SalesOrder> list(User user) {
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("status", PaymentStatus.PAID);
        params.put("user", user);
        return genericDaoSupport.searchForList("FROM SalesOrder WHERE disabled = false AND paymentStatus = :status AND user = :user", params);
    }
    
    /*
     * (non-Javadoc)
     * @see com.edooteach.api.servcice.SalesOrderService#create(com.edoomath.entity.user.User, com.edoomath.entity.user.UserAddress, com.edoomath.entity.course.Sku)
     */
    public SalesOrder create(User user, UserAddress userAddress, Sku sku, List<Long> courseIds) {
        
        if (StringUtils.isBlank(user.getMobile())) {
            throw BusinessException.newInstance("500", "请先绑定手机号");
        }
        
        SalesOrder salesOrder = new SalesOrder(sku.getIdString(), user, user.getMobile());
        genericDaoSupport.save(salesOrder);
        
        SalesOrderAddress salesOrderAddress = new SalesOrderAddress(salesOrder, userAddress.getReciver(), userAddress.getReciverMobile(), userAddress.getProvince(), userAddress.getCity(), userAddress.getDistrict(), userAddress.getAddress());
        genericDaoSupport.save(salesOrderAddress);
        
        // save all userBook
        List<Course> courses = courseDao.listByIds(courseIds);
        
        int totalPrice = 0;
        for(Course course : courses) {
            SalesOrderItem salesOrderItem = new SalesOrderItem(salesOrder, course, course.getPrice());
            genericDaoSupport.save(salesOrderItem);
            totalPrice = totalPrice + course.getPrice();
        }
        
        genericDaoSupport.update(salesOrder.price(totalPrice));
        
        return salesOrder;
    }

    /*
     * (non-Javadoc)
     * @see com.edooteach.api.servcice.SalesOrderService#load(java.lang.Long)
     */
    public SalesOrder load(Long id) {
        String sentence = "FROM SalesOrder WHERE disabled = false AND paymentStatus = :status AND id = :id";
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("status", PaymentStatus.PENDING);
        params.put("id", id);
        return genericDaoSupport.searchForObject(sentence, params, SalesOrder.class);
    }
    
    /*
     * (non-Javadoc)
     * @see com.edooteach.api.servcice.SalesOrderService#load(java.lang.String)
     */
    public SalesOrder load(String code) {
        String sentence = "FROM SalesOrder WHERE disabled = false AND code = :code";
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("code", code);
        return genericDaoSupport.searchForObject(sentence, params, SalesOrder.class);
    }
    
    /*
     * (non-Javadoc)
     * @see com.edooteach.api.servcice.SalesOrderService#prepay(com.edoomath.entity.recharge.RechargeOrder, com.edoomath.entity.user.User, java.lang.String)
     */
    public Map<String, Object> prepay(SalesOrder salesOrder, User user, String remoteIp) {
        
        try {
            
            WechatOpenid wechatOpenid = userDao.loadOpenid(user.getUnionid(), UserSource.EDOOMATH_WEAPP_ACCOUNT);
            
            // 1. create payment request
            PaymentRequest paymentRequest = new PaymentRequest(salesOrder.getCode());
            genericDaoSupport.save(paymentRequest.initliaze());
            
            logger.trace("#prepay() - Get remote IP address [{}].", remoteIp);
            Map<String, Object> parameters = new HashMap<String, Object>();
            parameters.put("order_no", paymentRequest.getOrderCode());
            parameters.put("request_no", paymentRequest.getCode());
            parameters.put("user_id", wechatOpenid.getOpenid());
            parameters.put("channel", "mallWeapppay");
            // FIXME salesOrder.getPrice()
            parameters.put("amount", 1);
            if(salesOrder.getType().equals(OrderType.LECTURE) || salesOrder.getType().equals(OrderType.MAIL)) {
                parameters.put("subject", "购买陆老师小课堂产品");  // FIXME
            } else if(salesOrder.getType().equals(OrderType.LECTURE)) {
                parameters.put("subject", "陆老师小课堂积分充值");  // FIXME
            }
            
            // 2. generate wechat pay context
            Map<String, Object> wechatPayContext = paymentHandler.generateWechatPayContext(parameters);
            logger.trace("#prepay() - Get wechatPayContext here [{}]", JsonUtils.toJson(wechatPayContext));
            
            return wechatPayContext;
        
        } catch (Exception e) {
            logger.error("#prepay - occurs error", e);
            throw BusinessException.newInstance("500", "充值支付失败");
        }
    }
    
    /*
     * (non-Javadoc)
     * @see com.edooteach.api.servcice.SalesOrderService#pay(com.edoomath.entity.trade.PaymentRequest, java.lang.String, java.lang.String, java.util.Date, int)
     */
    @SuppressWarnings("unchecked")
    public SalesOrder pay(PaymentRequest paymentRequest, String orderCode, String payCode, String payTime, int amount) {
        
        SalesOrder salesOrder = this.load(orderCode);
        
        if(salesOrder == null) {
            throw new BusinessException("支付回调订单数据有误");
        }
        
        // 1. update payment request
        genericDaoSupport.update(paymentRequest.paid(payCode));
        
        // 2. update recharge order
        genericDaoSupport.update(salesOrder.paid().processing());
        
        if(salesOrder.getType().equals(OrderType.CREDIT)) {
            
            UserCredit credit = userDao.loadCredit(salesOrder.getUser());
            if(credit != null) {
                credit.addRecharge(salesOrder.getCredits());
                genericDaoSupport.update(credit);
            } else {
                credit = new UserCredit(salesOrder.getUser());
                credit.addRecharge(salesOrder.getCredits());
                genericDaoSupport.save(credit);
            }
            
            User user = salesOrder.getUser();
            UserCreditRecorder userCreditRecorder = new UserCreditRecorder(user, "积分充值", salesOrder.getCredits(), ConsumeType.IN, ConsumeTag.CREDIT_RECHARGE);
            genericDaoSupport.save(userCreditRecorder.initliaze());
            
        } else {
            List<SalesOrderItem> salesOrderItems = genericDaoSupport.searchForList("FROM SalesOrderItem WHERE disabled = false AND salesOrder = :order", "order", salesOrder);
            for(SalesOrderItem salesOrderItem : salesOrderItems) {
                UserCourse userCourse = new UserCourse(salesOrder.getUser(), salesOrderItem.getCourse());
                genericDaoSupport.save(userCourse);
            }
            
            // 3. update userWallet
            User user = salesOrder.getUser();
            UserConsumeRecorder consumeRecorder = new UserConsumeRecorder(user, "购买练习册", amount, ConsumeType.OUT, ConsumeTag.BOOK_BUYING);
            genericDaoSupport.save(consumeRecorder.initliaze());
        }
        
        return salesOrder;
    }

}
